-- Lab2

import Control.Parallel
import Control.Monad
import System.Environment
import Control.Concurrent
import Control.Concurrent.MVar

f :: Double -> Double
f x = 2

getParams :: IO (Double, Double, Double, Double, Int)
getParams = do
  argv <- getArgs
  case argv of
    (a:b:eps:max_deriv2:n:[]) -> return (read a, read b, read eps, read max_deriv2, read n)
    _          -> error "usage: Main <a> <b> <epsilon> <max_of_2_derivative><nthreads>"

-- integration using method of rectangles
integrate :: (Double -> Double) -> (Double, Double) -> Double -> Int -> Double
integrate f (a, b) h n = h * (foldl (\sum i -> sum + f (a + h * (fromIntegral i - 0.5))) 0 [1..n])

calcStepsCount :: Double -> Double -> Double -> Double -> Int
calcStepsCount a b eps max_d2 = floor (sqrt ((b - a) ** 3 * max_d2 / eps / 24)) + 1

createIntervals :: Double -> Double -> Int -> [(Double, Double)]
createIntervals a b n = let h = (b - a) / fromIntegral n
                        in map (\i -> let i_ = fromIntegral i
                                      in (a + (i_ - 1) * h, a + i_ * h)) [1..n]

main = do
    params@(a, b, eps, max_d2, n) <- getParams
    print params
    let stepsPrecise = calcStepsCount a b eps max_d2
        steps = (stepsPrecise `div` n + 1) * n
        h = (b - a) / fromIntegral steps
    print $ "n = " ++ show steps ++ " h = " ++ show h ++ " (a, b) = " ++ show (a, b)
    print $ integrate f (a, b) h steps
    print $ createIntervals a b n
    childs <- mapM (thread f h (steps `div` n)) (createIntervals a b n)
    results <- mapM takeMVar childs
    print $ sum results
    where
        thread f_ h_ n_ range@(a_, b_) = do
            mvar <- newEmptyMVar
            forkIO (do
                let integral = integrate f_ range h_ n_
                putStrLn ("range = " ++ show range ++ " " ++ "J = " ++ show integral)
                putMVar mvar integral)
            return mvar
